from chess_pieces import ChessPiece, Ju, Ma, Xiang, Shi, King, Pao, Pawn

class GameRules:
    """象棋游戏规则类，负责验证移动的合法性和胜负判定"""
    
    @staticmethod
    def get_piece_at(pieces, row, col):
        """获取指定位置的棋子
        
        Args:
            pieces (list): 棋子列表
            row (int): 行坐标
            col (int): 列坐标
            
        Returns:
            ChessPiece or None: 位置上的棋子，如果没有则返回None
        """
        for piece in pieces:
            if piece.row == row and piece.col == col:
                return piece
        return None
    
    @staticmethod
    def is_valid_move(pieces, piece, from_row, from_col, to_row, to_col):
        """检查移动是否合法
        
        Args:
            pieces (list): 棋子列表
            piece (ChessPiece): 被移动的棋子
            from_row (int): 起始行
            from_col (int): 起始列
            to_row (int): 目标行
            to_col (int): 目标列
            
        Returns:
            bool: 移动是否合法
        """
        # 检查目标位置是否有己方棋子
        target_piece = GameRules.get_piece_at(pieces, to_row, to_col)
        if target_piece and target_piece.color == piece.color:
            return False
        
        # 根据棋子类型检查移动是否符合规则
        if isinstance(piece, Ju):
            return GameRules.is_valid_ju_move(pieces, from_row, from_col, to_row, to_col)
        elif isinstance(piece, Ma):
            return GameRules.is_valid_ma_move(pieces, from_row, from_col, to_row, to_col)
        elif isinstance(piece, Xiang):
            return GameRules.is_valid_xiang_move(pieces, piece.color, from_row, from_col, to_row, to_col)
        elif isinstance(piece, Shi):
            return GameRules.is_valid_shi_move(piece.color, from_row, from_col, to_row, to_col)
        elif isinstance(piece, King):
            return GameRules.is_valid_king_move(pieces, piece.color, from_row, from_col, to_row, to_col)
        elif isinstance(piece, Pao):
            return GameRules.is_valid_pao_move(pieces, from_row, from_col, to_row, to_col)
        elif isinstance(piece, Pawn):
            return GameRules.is_valid_pawn_move(piece.color, from_row, from_col, to_row, to_col)
        
        return False
    
    @staticmethod
    def is_valid_ju_move(pieces, from_row, from_col, to_row, to_col):
        """检查车的移动是否合法"""
        # 车只能横向或纵向移动
        if from_row != to_row and from_col != to_col:
            return False
        
        # 检查路径上是否有其他棋子
        if from_row == to_row:  # 横向移动
            start = min(from_col, to_col) + 1
            end = max(from_col, to_col)
            for col in range(start, end):
                if GameRules.get_piece_at(pieces, from_row, col):
                    return False
        else:  # 纵向移动
            start = min(from_row, to_row) + 1
            end = max(from_row, to_row)
            for row in range(start, end):
                if GameRules.get_piece_at(pieces, row, from_col):
                    return False
        
        return True
    
    @staticmethod
    def is_valid_ma_move(pieces, from_row, from_col, to_row, to_col):
        """检查马的移动是否合法"""
        # 计算行列差
        row_diff = abs(to_row - from_row)
        col_diff = abs(to_col - from_col)
        
        # 马走"日"字
        if not ((row_diff == 2 and col_diff == 1) or (row_diff == 1 and col_diff == 2)):
            return False
        
        # 检查是否有"蹩马腿"
        if row_diff == 2:  # 竖着走，检查横向阻挡
            block_row = from_row + (1 if to_row > from_row else -1)
            if GameRules.get_piece_at(pieces, block_row, from_col):
                return False
        else:  # 横着走，检查纵向阻挡
            block_col = from_col + (1 if to_col > from_col else -1)
            if GameRules.get_piece_at(pieces, from_row, block_col):
                return False
        
        return True
    
    @staticmethod
    def is_valid_xiang_move(pieces, color, from_row, from_col, to_row, to_col):
        """检查相/象的移动是否合法"""
        # 相/象只能走田字
        if abs(to_row - from_row) != 2 or abs(to_col - from_col) != 2:
            return False
        
        # 相/象不能过河
        if color == "red" and to_row < 5:
            return False
        elif color == "black" and to_row > 4:
            return False
        
        # 检查"塞象眼"
        center_row = (from_row + to_row) // 2
        center_col = (from_col + to_col) // 2
        if GameRules.get_piece_at(pieces, center_row, center_col):
            return False
        
        return True
    
    @staticmethod
    def is_valid_shi_move(color, from_row, from_col, to_row, to_col):
        """检查士/仕的移动是否合法"""
        # 士/仕只能斜着走一步
        if abs(to_row - from_row) != 1 or abs(to_col - from_col) != 1:
            return False
        
        # 士/仕只能在九宫格内移动
        if color == "red":
            if to_row < 7 or to_row > 9 or to_col < 3 or to_col > 5:
                return False
        else:  # black
            if to_row < 0 or to_row > 2 or to_col < 3 or to_col > 5:
                return False
        
        return True
    
    @staticmethod
    def is_valid_king_move(pieces, color, from_row, from_col, to_row, to_col):
        """检查将/帅的移动是否合法"""
        # 将/帅特殊规则：可以直接吃对方的将/帅（将帅对脸）
        target_piece = GameRules.get_piece_at(pieces, to_row, to_col)
        if isinstance(target_piece, King) and target_piece.color != color:
            # 检查是否在同一列
            if from_col == to_col:
                # 检查中间是否有其他棋子
                start = min(from_row, to_row) + 1
                end = max(from_row, to_row)
                has_piece_between = False
                for row in range(start, end):
                    if GameRules.get_piece_at(pieces, row, from_col):
                        has_piece_between = True
                        break
                
                if not has_piece_between:
                    return True
        
        # 将/帅只能上下左右走一步
        if (abs(to_row - from_row) + abs(to_col - from_col)) != 1:
            return False
        
        # 将/帅只能在九宫格内移动
        if color == "red":
            if to_row < 7 or to_row > 9 or to_col < 3 or to_col > 5:
                return False
        else:  # black
            if to_row < 0 or to_row > 2 or to_col < 3 or to_col > 5:
                return False
        
        return True
    
    @staticmethod
    def is_valid_pao_move(pieces, from_row, from_col, to_row, to_col):
        """检查炮的移动是否合法"""
        # 炮只能横向或纵向移动
        if from_row != to_row and from_col != to_col:
            return False
        
        # 检查目标位置是否有棋子
        target_piece = GameRules.get_piece_at(pieces, to_row, to_col)
        
        # 计算路径上的棋子数量
        pieces_in_path = 0
        if from_row == to_row:  # 横向移动
            start = min(from_col, to_col) + 1
            end = max(from_col, to_col)
            for col in range(start, end):
                if GameRules.get_piece_at(pieces, from_row, col):
                    pieces_in_path += 1
        else:  # 纵向移动
            start = min(from_row, to_row) + 1
            end = max(from_row, to_row)
            for row in range(start, end):
                if GameRules.get_piece_at(pieces, row, from_col):
                    pieces_in_path += 1
        
        # 吃子时必须有且只有一个炮架
        if target_piece:
            return pieces_in_path == 1
        
        # 移动时不能有棋子阻隔
        return pieces_in_path == 0
    
    @staticmethod
    def is_valid_pawn_move(color, from_row, from_col, to_row, to_col):
        """检查兵/卒的移动是否合法"""
        # 兵/卒只能走一步
        if abs(to_row - from_row) + abs(to_col - from_col) != 1:
            return False
        
        if color == "red":
            # 红方兵不能后退
            if to_row > from_row:
                return False
            
            # 未过河不能横走
            if from_row >= 5 and to_row == from_row:
                return False
        else:  # black
            # 黑方卒不能后退
            if to_row < from_row:
                return False
            
            # 未过河不能横走
            if from_row <= 4 and to_row == from_row:
                return False
        
        return True
    
    @staticmethod
    def calculate_possible_moves(pieces, piece):
        """计算棋子所有可能的移动位置
        
        Args:
            pieces (list): 棋子列表
            piece (ChessPiece): 要计算的棋子
            
        Returns:
            list: 可能移动的位置列表 [(row, col), ...]
        """
        moves = []
        capturable = []
        
        # 遍历所有可能的位置
        for row in range(10):
            for col in range(9):
                # 检查移动是否合法
                if GameRules.is_valid_move(pieces, piece, piece.row, piece.col, row, col):
                    # 检查目标位置是否有对方棋子（可吃子）
                    target = GameRules.get_piece_at(pieces, row, col)
                    if target:
                        capturable.append((row, col))
                    moves.append((row, col))
        
        return moves, capturable
    
    @staticmethod
    def is_checkmate(pieces, color):
        """检查是否将军
        
        Args:
            pieces (list): 棋子列表
            color (str): 要检查的方的颜色
            
        Returns:
            bool: 是否将军
        """
        # 找出该方的将/帅
        king = None
        for piece in pieces:
            if isinstance(piece, King) and piece.color == color:
                king = piece
                break
        
        if not king:
            return True  # 没有找到将/帅，视为被将死
        
        # 检查对方每个棋子是否能吃掉将/帅
        for piece in pieces:
            if piece.color != color:  # 对方棋子
                if GameRules.is_valid_move(pieces, piece, piece.row, piece.col, king.row, king.col):
                    return True
        
        return False
    
    @staticmethod
    def can_move_to(pieces, piece, to_row, to_col):
        """检查棋子是否可以移动到指定位置"""
        return GameRules.is_valid_move(pieces, piece, piece.row, piece.col, to_row, to_col)
    
    @staticmethod
    def is_game_over(pieces, player_color):
        """检查游戏是否结束
        
        Args:
            pieces (list): 棋子列表
            player_color (str): 当前玩家颜色
            
        Returns:
            bool: 游戏是否结束
            str or None: 获胜方，如果游戏未结束则为None
        """
        # 检查对方是否还有将/帅
        opponent_color = "black" if player_color == "red" else "red"
        opponent_king = None
        
        for piece in pieces:
            if isinstance(piece, King) and piece.color == opponent_color:
                opponent_king = piece
                break
        
        # 没有找到对方的将/帅，当前玩家获胜
        if not opponent_king:
            return True, player_color
        
        # 检查对方是否被将军
        if GameRules.is_checkmate(pieces, opponent_color):
            # 检查对方是否有合法移动可以解除将军
            has_valid_move = False
            for piece in pieces:
                if piece.color == opponent_color:
                    for row in range(10):
                        for col in range(9):
                            # 尝试移动
                            if GameRules.is_valid_move(pieces, piece, piece.row, piece.col, row, col):
                                # 模拟移动并检查是否解除将军
                                original_row, original_col = piece.row, piece.col
                                target_piece = GameRules.get_piece_at(pieces, row, col)
                                
                                # 暂时移除目标位置的棋子（如果有）
                                if target_piece:
                                    pieces.remove(target_piece)
                                
                                # 移动棋子
                                piece.row, piece.col = row, col
                                
                                # 检查是否解除将军
                                still_check = GameRules.is_checkmate(pieces, opponent_color)
                                
                                # 恢复移动
                                piece.row, piece.col = original_row, original_col
                                
                                # 恢复被移除的棋子（如果有）
                                if target_piece:
                                    pieces.append(target_piece)
                                
                                if not still_check:
                                    has_valid_move = True
                                    break
                        if has_valid_move:
                            break
                if has_valid_move:
                    break
            
            # 如果对方没有合法移动可以解除将军，则当前玩家获胜
            if not has_valid_move:
                return True, player_color
        
        return False, None 